﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;

namespace FindPath
{
    public partial class frmLogin : Form
    {
        private Thread listenThread = null;
        private int userId = 0;
        private string userPassword = "";
        private TsCharacter thisCharacter = null;
        private List<Player> playerList = new List<Player>();
        private PetDetail[] petPanelList = new PetDetail[6];

        private volatile bool bActive = false;
        delegate void SetTextCallback(string log, bool clear);
        delegate void SetByteCallback(byte[] data, bool clear);
        delegate void SetMessageCallback(List<TsMessage> messages, bool clear);
        delegate void SetPlayerCallback(List<Player> playerData);
        delegate void SetCharacterCallback(TsCharacter characterData);
        delegate void SetInventoryCallback(PlayerItem[] items);
        delegate void SetUniformCallback(PlayerItem[] uniforms);
        delegate void SetPetCallback();
        delegate void SetDefaultPetCallback();
        delegate void SetUpdatePacketCallback();
        public frmLogin()
        {
            InitializeComponent();
            petPanelList[0] = petDetail1;
            petPanelList[1] = petDetail2;
            petPanelList[2] = petDetail3;
            petPanelList[3] = petDetail4;
        }

        private void frmLogin_Load(object sender, EventArgs e)
        {
            SplashForm splashFrm = new SplashForm();
            splashFrm.ShowDialog();
            this.FormClosed += new FormClosedEventHandler(frmLogin_Unload);
        }
        private void frmLogin_Unload(object sender, FormClosedEventArgs e)
        {
            if (this.listenThread != null)
            {
                this.listenThread.Abort();
                this.listenThread.Join();
            }
        }

        private void btnLogin_Click(object sender, EventArgs e)
        {
            
            string userIdStr = txtUsername.Text;
            userPassword = txtPassword.Text;
            int version = int.Parse(txtVersion.Text);
            if (userIdStr != null && !userIdStr.Equals("") && userPassword != null && !userPassword.Equals(""))
            {
                try
                {
                    
                    userId = int.Parse(userIdStr);
                    updateLog("Connecting...");
                    if (WSUtils.openSocket("210.242.35.87", 6414))
                    {
                        bActive = true;
                        listenThread = new Thread(new ThreadStart(ListenThread));
                        listenThread.Name = "LISTEN THREAD";
                        listenThread.IsBackground = true;
                        listenThread.Start();
                        while (!listenThread.IsAlive) ;
                        timerUpdateTime.Enabled = true;
                        //updateLog("Listening...");
                        //TcpClient tcpClient = WSUtils.getTCPClient();
                        //StateObject stateObject = new StateObject();
                        //stateObject.workSocket = tcpClient.Client;
                        //tcpClient.Client.BeginReceive(stateObject.Buffer, 0, StateObject.BUFFER_SIZE, 0, new AsyncCallback(receiveCallback), stateObject);

                        if (WSUtils.sendData("00"))
                        {
                            updateLog("SendingLoginRequest...");
                            thisCharacter = new TsCharacter { playerId = userId };
                            WSUtils.login(userId, userPassword, "WR", version);
                        }
                        else
                        {
                            updateLog("Connection Closed");
                        }
                    }
                    else
                    {
                        updateLog("Can't open Socket");
                    }

                    

                    
                }
                catch (Exception ex)
                {
                    if (listenThread != null)
                    {
                        bActive = false;
                        listenThread.Join();
                    }
                    rtcLog.Text += ex.Message + ex.StackTrace + "\n";
                }
                
            }

            //rtcLog.Clear();
            
            //rtcLog.Text = WSUtils.encodeNumber(int.Parse(tempTxt), 2);
            //rtcLog.Text = WSUtils.decodeNumber(tempTxt, 2).ToString();
            //rtcLog.Text = WSUtils.encodeString(tempTxt);
            //rtcLog.Text = WSUtils.decodeNumber(tempTxt, 4).ToString();
            
            //WSUtils.sendData("00");
                                
            //WSUtils.sendData("01087AC000005752BA007061726164697365");
            
        }

        private void lstInventory_MouseDown(Object sender, MouseEventArgs e)
        {
            if (lstInventory.SelectedItems.Count != 0)
            {
                ListViewItem selectedItem = lstInventory.SelectedItems[0];
                if (selectedItem != null && selectedItem.Tag != null)
                {
                    PlayerItem itemData = (PlayerItem) selectedItem.Tag;
                    if (e.Button == MouseButtons.Left)
                    {
                        lblItemDetail.Text = itemData.description;
                    }
                    else if (e.Button == MouseButtons.Right)
                    {
                        //Show ContextMenu here
                        cmnuInventory.Show(lstInventory.PointToScreen(e.Location));
                    }
                }
                
            }
            
        }

        public void updatePacketCount()
        {
            if (tslblPacketRecv.Tag == null)
            {
                tslblPacketRecv.Tag = 1;
                tslblPacketRecv.Text = "Received: " + 1;
            }
            else
            {
                int currentPacketCount = (int) tslblPacketRecv.Tag;
                currentPacketCount++;
                tslblPacketRecv.Tag = currentPacketCount;
                tslblPacketRecv.Text = "Received: " + currentPacketCount;

            }


        }

        public void updateLog(string log, bool clear = false)
        {
            if (rtcLog.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(updateLog);
                if (this != null)
                {
                    this.BeginInvoke(d, new object[] { log, clear });
                }

            }
            else
            {
                if (clear)
                {
                    this.rtcLog.Clear();
                }
                string[] packetLogs = log.Split(new string[] { "F4 44" }, StringSplitOptions.RemoveEmptyEntries);
                foreach (string packet in packetLogs)
                {
                    this.rtcLog.Text += (packet);
                }
            }

        }

        public void updateLog(byte[] data, bool clear = false)
        {
            if (rtcLog.InvokeRequired)
            {
                SetByteCallback d = new SetByteCallback(updateLog);
                if (this != null)
                {
                    this.BeginInvoke(d, new object[] { data, clear });
                }

            }
            else
            {
                if (clear)
                {
                    this.rtcLog.Clear();
                }
                string log = WSUtils.printBytes(data, data.Length);
                string[] packetLogs = log.Split(new string[] { "F4 44" }, StringSplitOptions.RemoveEmptyEntries);
                foreach (string packet in packetLogs)
                {
                    this.rtcLog.Text += (packet + "\n");
                }
            }
        }

        public void updateLog(List<TsMessage> messages, bool clear = false)
        {
            if (rtcLog.InvokeRequired)
            {
                SetMessageCallback d = new SetMessageCallback(updateLog);
                rtcLog.BeginInvoke(d, new object[] { messages, clear });

            }
            else
            {
                if (clear)
                {
                    this.rtcLog.Clear();
                }
                
                foreach (TsMessage message in messages)
                {
                    //rtcLog.Text += ("BEGIN " + WSUtils.printBytes(message.data, message.data.Length) + "\n");
                    Debug.WriteLine(message.ToString());
                }
            }
        }
        //Missing update maxHP + maxSP
        public void updatePetAttr(int index, byte type, int value)
        {
            PetDetail petDetailPanel = petPanelList[index - 1];
            Pet petData = null;
            if (thisCharacter != null && thisCharacter.carryPet != null)
            {
                petData = thisCharacter.carryPet[index - 1];
            }
            else
            {
                //petData = new Pet();
                //thisCharacter.carryPet[index - 1] = petData;
            }
            if (petDetailPanel != null && petData != null)
            {
                switch (type)
                {
                    case CommandConstants.UDPATE_TOTAL_EXP:
                        petDetailPanel.BeginInvoke(new Action<int, int>((petIdx, tExp) =>
                        {
                            PetDetail petPanel = petPanelList[petIdx - 1];
                            Pet pet = thisCharacter.carryPet[petIdx - 1];
                            if (petPanel != null && petData != null)
                            {
                                //petPanel.petCurExp = tExp;
                                pet.totalExp = tExp;
                                petPanel.petCurExp = (pet.totalExp - Global.expChart[((byte)pet.petType), pet.petLevel - 1]);
                            }
                            
                        }), new object[] { index, value });
                        break;
                    case CommandConstants.UPDATE_ADD_AGI:
                        petDetailPanel.BeginInvoke(new Action<int, int>((petIdx, agiStt) =>
                        {
                            PetDetail petPanel = petPanelList[petIdx - 1];
                            Pet pet = thisCharacter.carryPet[petIdx - 1];
                            if (petPanel != null && pet != null)
                            {
                                pet.addAgiStatus = agiStt;
                                if (pet.addAgiStatus > 0)
                                {
                                    petPanel.agiStt = pet.agiStatus + " + " + pet.addAgiStatus + " = " + (pet.agiStatus + pet.addAgiStatus); ;
                                }
                                else if (pet.addAgiStatus < 0)
                                {
                                    petPanel.agiStt = pet.agiStatus + " - " + Math.Abs(pet.addAgiStatus) + " = " + (pet.agiStatus + pet.addAgiStatus); ;
                                }
                                else
                                {
                                    petPanel.agiStt = pet.agiStatus + "";
                                }
                            }
                        }), new object[] {index, value });
                        break;
                    case CommandConstants.UPDATE_ADD_ATK:
                        petDetailPanel.BeginInvoke(new Action<int, int>((petIdx, atkStt) =>
                        {
                            PetDetail petPanel = petPanelList[petIdx - 1];
                            Pet pet = thisCharacter.carryPet[petIdx - 1];
                            if (petPanel != null && pet != null)
                            {
                                pet.addAtkStatus = atkStt;
                                if (pet.addAtkStatus > 0)
                                {
                                    petPanel.atkStt = pet.atkStatus + " + " + pet.addAtkStatus + " = " + (pet.atkStatus + pet.addAtkStatus);
                                }
                                else if (pet.addAgiStatus < 0)
                                {
                                    petPanel.atkStt = pet.atkStatus + " - " + Math.Abs(pet.addAtkStatus) + " = " + (pet.atkStatus + pet.addAtkStatus);
                                }
                                else
                                {
                                    petPanel.atkStt = pet.atkStatus + "";
                                }
                            }
                        }), new object[] {index, value });
                        break;
                    case CommandConstants.UPDATE_ADD_DEF:
                        petDetailPanel.BeginInvoke(new Action<int, int>((petIdx, defStt) =>
                        {
                            PetDetail petPanel = petPanelList[petIdx - 1];
                            Pet pet = thisCharacter.carryPet[petIdx - 1];
                            if (petPanel != null && pet != null)
                            {
                                pet.addDefStatus = defStt;
                                if (pet.addDefStatus > 0)
                                {
                                    petPanel.defStt = pet.defStatus + " + " + pet.addDefStatus + " = " + (pet.defStatus + pet.addDefStatus);
                                }
                                else if (pet.addAgiStatus < 0)
                                {
                                    petPanel.defStt = pet.defStatus + " - " + Math.Abs(pet.addDefStatus) + " = " + (pet.defStatus + pet.addDefStatus);
                                }
                                else
                                {
                                    petPanel.defStt = pet.defStatus + "";
                                }
                            }
                        }), new object[] {index,  value });
                        break;
                    case CommandConstants.UPDATE_ADD_INT:
                        petDetailPanel.BeginInvoke(new Action<int, int>((petIdx, intStt) =>
                        {
                            PetDetail petPanel = petPanelList[petIdx - 1];
                            Pet pet = thisCharacter.carryPet[petIdx - 1];
                            if (petPanel != null && pet != null)
                            {
                                pet.addIntStatus = intStt;
                                if (pet.addIntStatus > 0)
                                {
                                    petPanel.intStt = pet.intStatus + " + " + pet.addIntStatus + " = " + (pet.intStatus + pet.addIntStatus);
                                }
                                else if (pet.addIntStatus < 0)
                                {
                                    petPanel.intStt = pet.intStatus + " - " + Math.Abs(pet.addIntStatus) + " = " + (pet.intStatus + pet.addIntStatus);
                                }
                                else
                                {
                                    petPanel.intStt = pet.intStatus + "";
                                }
                            }
                        }), new object[] {index, value });
                        break;
                    case CommandConstants.UPDATE_AGI:
                        petDetailPanel.BeginInvoke(new Action<int, int>((petIdx, agiStt) =>
                        {
                            PetDetail petPanel = petPanelList[petIdx - 1];
                            Pet pet = thisCharacter.carryPet[petIdx - 1];
                            if (petPanel != null && pet != null)
                            {
                                pet.agiStatus = agiStt;
                                if (pet.addAgiStatus > 0)
                                {
                                    petPanel.agiStt = pet.agiStatus + " + " + pet.addAgiStatus + " = " + (pet.agiStatus + pet.addAgiStatus);
                                }
                                else if (pet.addAgiStatus < 0)
                                {
                                    petPanel.agiStt = pet.agiStatus + " - " + Math.Abs(pet.addAgiStatus) + " = " + (pet.agiStatus + pet.addAgiStatus);
                                }
                                else
                                {
                                    petPanel.agiStt = pet.agiStatus + "";
                                }
                            }
                        }), new object[] {index, value });
                        break;
                    case CommandConstants.UPDATE_ATK:
                        petDetailPanel.BeginInvoke(new Action<int, int>((petIdx, atkStt) =>
                        {
                            PetDetail petPanel = petPanelList[petIdx - 1];
                            Pet pet = thisCharacter.carryPet[petIdx - 1];
                            if (petPanel != null && pet != null)
                            {
                                pet.atkStatus = atkStt;
                                if (pet.addAtkStatus > 0)
                                {
                                    petPanel.atkStt = pet.atkStatus + " + " + pet.addAtkStatus + " = " + (pet.atkStatus + pet.addAtkStatus);
                                }
                                else if (pet.addAgiStatus < 0)
                                {
                                    petPanel.atkStt = pet.atkStatus + " - " + Math.Abs(pet.addAtkStatus) + " = " + (pet.atkStatus + pet.addAtkStatus);
                                }
                                else
                                {
                                    petPanel.atkStt = pet.atkStatus + "";
                                }
                            }
                        }), new object[] {index, value });
                        break;
                    case CommandConstants.UPDATE_HP:
                        petDetailPanel.BeginInvoke(new Action<int, int>((petIdx, curHP) =>
                        {
                            PetDetail petPanel = petPanelList[petIdx - 1];
                            Pet pet = thisCharacter.carryPet[petIdx - 1];
                            if (petPanel != null && pet != null)
                            {
                                pet.curHP = curHP;
                                petPanel.petCurHp = curHP;
                            }
                        }), new object[] { index, value });
                        break;
                    case CommandConstants.UPDATE_HPX:
                        petDetailPanel.BeginInvoke(new Action<int, int>((petIdx, hpxStt) =>
                        {
                            PetDetail petPanel = petPanelList[petIdx - 1];
                            Pet pet = thisCharacter.carryPet[petIdx - 1];
                            if (petPanel != null && pet != null)
                            {
                                pet.hpStatus = hpxStt;
                                petPanel.hpxStt = hpxStt + "";
                            }
                        }), new object[] { index, value });
                        break;
                    case CommandConstants.UPDATE_INT:
                        petDetailPanel.BeginInvoke(new Action<int, int>((petIdx, intStt) =>
                        {
                            PetDetail petPanel = petPanelList[petIdx - 1];
                            Pet pet = thisCharacter.carryPet[petIdx - 1];
                            if (petPanel != null && pet != null)
                            {
                                pet.addIntStatus = intStt;
                                if (pet.addIntStatus > 0)
                                {
                                    petPanel.intStt = pet.intStatus + " + " + pet.addIntStatus + " = " + (pet.intStatus + pet.addIntStatus);
                                }
                                else if (pet.addIntStatus < 0)
                                {
                                    petPanel.intStt = pet.intStatus + " - " + Math.Abs(pet.addIntStatus) + " = " + (pet.intStatus + pet.addIntStatus);
                                }
                                else
                                {
                                    petPanel.intStt = pet.intStatus + "";
                                }
                            }
                        }), new object[] {index, value });
                        break;
                    case CommandConstants.UPDATE_SP:
                        petDetailPanel.BeginInvoke(new Action<int, int>((petIdx, curSP) =>
                        {
                            PetDetail petPanel = petPanelList[petIdx - 1];
                            Pet pet = thisCharacter.carryPet[petIdx - 1];
                            if (petPanel != null && pet != null)
                            {
                                pet.curSP = curSP;
                                petPanel.petCurSp = curSP;
                            }
                        }), new object[] {index, value });
                        break;
                    case CommandConstants.UPDATE_SPX:
                        petDetailPanel.BeginInvoke(new Action<int, int>((petIdx, spxStt) =>
                        {
                            PetDetail petPanel = petPanelList[petIdx - 1];
                            Pet pet = thisCharacter.carryPet[petIdx - 1];
                            if (petPanel != null && pet != null)
                            {
                                pet.spStatus = spxStt;
                                petPanel.spxStt = spxStt + "";
                            }
                        }), new object[] { index, value });
                        break;
                    case CommandConstants.UPDATE_LEVEL:
                        petDetailPanel.BeginInvoke(new Action<int, int>((petIdx, curLvl) =>
                        {
                            PetDetail petPanel = petPanelList[petIdx - 1];
                            Pet pet = thisCharacter.carryPet[petIdx - 1];
                            if (petPanel != null && pet != null)
                            {
                                pet.petLevel = (byte)curLvl;
                                petPanel.petLevel = (byte)curLvl;
                                petPanel.petCurExp = (pet.totalExp - Global.expChart[((byte)pet.petType), pet.petLevel - 1]);
                                petPanel.petMaxExp = (Global.expChart[(byte)pet.petType, pet.petLevel] - Global.expChart[(byte)pet.petType, pet.petLevel - 1]);
                                
                            }
                        }), new object[] { index, value });
                        break;

                }
            }
            else
            {
                Debug.WriteLine("NULL " + (petData != null) + " " + (petDetailPanel != null) );
            }
        }

        public void updatePlayerAttr(byte type, int value)
        {
            switch (type)
            {
                case CommandConstants.UDPATE_TOTAL_EXP:
                    lblCurExp.BeginInvoke(new Action<int>((curExp) =>
                    {
                        thisCharacter.totalExp = curExp;
                        lblCurExp.Text = (thisCharacter.totalExp - Global.expChart[((byte)thisCharacter.playerType), thisCharacter.playerLevel - 1]) + "";
                    }), new object[] { value });
                    break;
                case CommandConstants.UPDATE_ADD_AGI:
                    lblAgiDetail.BeginInvoke(new Action<int>((agiStt) =>
                    {
                        thisCharacter.addAgiStatus = agiStt;
                        if (thisCharacter.addAgiStatus > 0)
                        {
                            lblAgiDetail.Text = thisCharacter.agiStatus + " + " + thisCharacter.addAgiStatus + " = " + (thisCharacter.agiStatus + thisCharacter.addAgiStatus); ;
                        }
                        else if (thisCharacter.addAgiStatus < 0)
                        {
                            lblAgiDetail.Text = thisCharacter.agiStatus + " - " + Math.Abs(thisCharacter.addAgiStatus) + " = " + (thisCharacter.agiStatus + thisCharacter.addAgiStatus); ;
                        }
                        else
                        {
                            lblAgiDetail.Text = thisCharacter.agiStatus + "";
                        }
                    }), new object[] { value });
                    break;
                case CommandConstants.UPDATE_ADD_ATK:
                    lblAtkDetail.BeginInvoke(new Action<int>((atkStt) =>
                    {
                        thisCharacter.addAtkStatus = atkStt;
                        if (thisCharacter.addAtkStatus > 0)
                        {
                            lblAtkDetail.Text = thisCharacter.atkStatus + " + " + thisCharacter.addAtkStatus + " = " + (thisCharacter.atkStatus + thisCharacter.addAtkStatus);
                        }
                        else if (thisCharacter.addAgiStatus < 0)
                        {
                            lblAtkDetail.Text = thisCharacter.atkStatus + " - " + Math.Abs(thisCharacter.addAtkStatus) + " = " + (thisCharacter.atkStatus + thisCharacter.addAtkStatus);
                        }
                        else
                        {
                            lblAtkDetail.Text = thisCharacter.atkStatus + "";
                        }
                    }), new object[] { value });
                    break;
                case CommandConstants.UPDATE_ADD_DEF:
                    lblDefDetail.BeginInvoke(new Action<int>((defStt) =>
                    {
                        thisCharacter.addDefStatus = defStt;
                        if (thisCharacter.addDefStatus > 0)
                        {
                            lblDefDetail.Text = thisCharacter.defStatus + " + " + thisCharacter.addDefStatus + " = " + (thisCharacter.defStatus + thisCharacter.addDefStatus);
                        }
                        else if (thisCharacter.addAgiStatus < 0)
                        {
                            lblDefDetail.Text = thisCharacter.defStatus + " - " + Math.Abs(thisCharacter.addDefStatus) + " = " + (thisCharacter.defStatus + thisCharacter.addDefStatus);
                        }
                        else
                        {
                            lblDefDetail.Text = thisCharacter.defStatus + "";
                        }
                    }), new object[] { value });
                    break;
                case CommandConstants.UPDATE_ADD_INT:
                    lblIntDetail.BeginInvoke(new Action<int>((intStt) =>
                    {
                        thisCharacter.addIntStatus = intStt;
                        if (thisCharacter.addIntStatus > 0)
                        {
                            lblIntDetail.Text = thisCharacter.intStatus + " + " + thisCharacter.addIntStatus + " = " + (thisCharacter.intStatus + thisCharacter.addIntStatus);
                        }
                        else if (thisCharacter.addIntStatus < 0)
                        {
                            lblIntDetail.Text = thisCharacter.intStatus + " - " + Math.Abs(thisCharacter.addIntStatus) + " = " + (thisCharacter.intStatus + thisCharacter.addIntStatus);
                        }
                        else
                        {
                            lblIntDetail.Text = thisCharacter.intStatus + "";
                        }
                    }), new object[] { value });
                    break;
                case CommandConstants.UPDATE_AGI:
                    lblAgiDetail.BeginInvoke(new Action<int>((agiStt) =>
                    {
                        thisCharacter.agiStatus = agiStt;
                        if (thisCharacter.addAgiStatus > 0)
                        {
                            lblAgiDetail.Text = thisCharacter.agiStatus + " + " + thisCharacter.addAgiStatus + " = " + (thisCharacter.agiStatus + thisCharacter.addAgiStatus);
                        }
                        else if (thisCharacter.addAgiStatus < 0)
                        {
                            lblAgiDetail.Text = thisCharacter.agiStatus + " - " + Math.Abs(thisCharacter.addAgiStatus) + " = " + (thisCharacter.agiStatus + thisCharacter.addAgiStatus);
                        }
                        else
                        {
                            lblAgiDetail.Text = thisCharacter.agiStatus + "";
                        }
                    }), new object[] { value });
                    break;
                case CommandConstants.UPDATE_ATK:
                    lblAtkDetail.BeginInvoke(new Action<int>((atkStt) =>
                    {
                        thisCharacter.atkStatus = atkStt;
                        if (thisCharacter.addAtkStatus > 0)
                        {
                            lblAtkDetail.Text = thisCharacter.atkStatus + " + " + thisCharacter.addAtkStatus + " = " + (thisCharacter.atkStatus + thisCharacter.addAtkStatus);
                        }
                        else if (thisCharacter.addAgiStatus < 0)
                        {
                            lblAtkDetail.Text = thisCharacter.atkStatus + " - " + Math.Abs(thisCharacter.addAtkStatus) + " = " + (thisCharacter.atkStatus + thisCharacter.addAtkStatus);
                        }
                        else
                        {
                            lblAtkDetail.Text = thisCharacter.atkStatus + "";
                        }
                    }), new object[] { value });
                    break;
                case CommandConstants.UPDATE_HP:
                    lblCurHp.BeginInvoke(new Action<int>((curHP) =>
                    {
                        thisCharacter.curHP = curHP;
                        lblCurHp.Text = curHP + "";
                    }), new object[] { value });
                    break;
                case CommandConstants.UPDATE_HPX:
                    lblHpxDetail.BeginInvoke(new Action<int>((hpxStt) =>
                    {
                        thisCharacter.hpStatus = hpxStt;
                        lblHpxDetail.Text = thisCharacter.hpStatus + "";
                    }), new object[] { value });
                    break;
                case CommandConstants.UPDATE_INT:
                    lblIntDetail.BeginInvoke(new Action<int>((intStt) =>
                    {
                        thisCharacter.addIntStatus = intStt;
                        if (thisCharacter.addIntStatus > 0)
                        {
                            lblIntDetail.Text = thisCharacter.intStatus + " + " + Math.Abs(thisCharacter.addIntStatus) + " = " + (thisCharacter.intStatus + thisCharacter.addIntStatus);
                        }
                        else if (thisCharacter.addIntStatus < 0)
                        {
                            lblIntDetail.Text = thisCharacter.intStatus + " - " + Math.Abs(thisCharacter.addIntStatus) + " = " + (thisCharacter.intStatus + thisCharacter.addIntStatus);
                        }
                        else
                        {
                            lblIntDetail.Text = thisCharacter.intStatus + "";
                        }
                    }), new object[] { value });
                    break;
                case CommandConstants.UPDATE_SP:
                    lblCurSp.BeginInvoke(new Action<int>((curSP) =>
                    {
                        thisCharacter.curSP = curSP;
                        lblCurSp.Text = curSP + "";
                    }), new object[] { value });
                    break;
                case CommandConstants.UPDATE_SPX:
                    lblSpxDetail.BeginInvoke(new Action<int>((spxStt) =>
                    {
                        thisCharacter.spStatus = spxStt;
                        lblSpxDetail.Text = thisCharacter.spStatus + "";
                    }), new object[] { value });
                    break;
                case CommandConstants.UPDATE_LEVEL:
                    lblLvl.BeginInvoke(new Action<int>((curLvl) =>
                    {
                        thisCharacter.playerLevel = (byte)curLvl;
                        lblCurExp.Text = (thisCharacter.totalExp - Global.expChart[((byte)thisCharacter.playerType), thisCharacter.playerLevel - 1]) + "";
                        lblMaxExp.Text = "/ " + (Global.expChart[(byte)thisCharacter.playerType, thisCharacter.playerLevel] - Global.expChart[(byte)thisCharacter.playerType, thisCharacter.playerLevel - 1]);
                        lblLvl.Text = thisCharacter.playerLevel + "";
                    }), new object[] { value });
                    break;
                case CommandConstants.UPDATE_STATUS_POINT:
                    grpStatus.BeginInvoke(new Action<int>((sttPoint) =>
                    {
                        thisCharacter.statusPointLeft = sttPoint;
                        grpStatus.Text = "Point Left: " + sttPoint;

                    }), new object[] { value });
                    break;

            }
        }
        public void updateDefaultPet(int petId)
        {
            this.BeginInvoke(new Action<int>((defaultId) =>
            {
                if (thisCharacter != null)
                {
                    if (thisCharacter.carryPet != null)
                    {
                        for (int i = 0; i < thisCharacter.carryPet.Length; i++)
                        {
                            Pet pet = thisCharacter.carryPet[i];
                            if (pet != null && pet.petId == petId)
                            {
                                thisCharacter.defaultPet = petId;
                                foreach (PetDetail panel in petPanelList)
                                {
                                    if (panel != null)
                                    {
                                        panel.IsActive = false;
                                    }
                                }
                                PetDetail petPanel = petPanelList[i];
                                if (petPanel != null)
                                {
                                    petPanel.IsActive = true;
                                }
                                txtPetName.Text = pet.petName;
                                lblPetLvl.Text = pet.petLevel + "";
                                lblPetCurHp.Text = pet.curHP + "";
                                lblPetMaxHp.Text = "/ " + pet.maxHP + "";
                                lblPetCurSp.Text = pet.curSP + "";
                                lblPetMaxSp.Text = "/ " + pet.maxSP + "";
                                lblPetCurExp.Text = (pet.totalExp - (Global.expChart[(byte)pet.petType, pet.petLevel - 1])) + "";
                                lblPetMaxExp.Text = "/ " + (Global.expChart[(byte)pet.petType, pet.petLevel] - Global.expChart[(byte) pet.petType, (pet.petLevel - 1)]) + "";
                                break;
                            }
                        }
                    }
                }
                
            }
            ), new object[] { petId });
        }
        public void updatePetInfo(Pet[] listPets) 
        {
            this.Invoke(new Action<Pet[]>((petList) =>
                {
                    for (int i = 0; i < petList.Length; i++)
                    {
                        Pet pet = petList[i];
                        if (thisCharacter.carryPet != null && thisCharacter.carryPet[i] != null)
                        {
                            Pet storedPet = thisCharacter.carryPet[i];
                            pet.addIntStatus = storedPet.addIntStatus;
                            pet.addAtkStatus = storedPet.addAtkStatus;
                            pet.addAgiStatus = storedPet.addAgiStatus;
                            pet.addDefStatus = storedPet.addDefStatus;
                            pet.curHP = storedPet.curHP;
                            pet.curSP = storedPet.curSP;
                        }
                        else
                        {
                            thisCharacter.carryPet[i] = pet;
                        }
                        PetDetail petPanel = (PetDetail)petPanelList[i];
                        if (petPanel != null)
                        {
                            if (pet != null)
                            {
                                petPanel.petLevel = pet.petLevel;
                                petPanel.petName = pet.petName;
                                petPanel.petCurHp = pet.curHP;
                                petPanel.petMaxHp = pet.maxHP;
                                petPanel.petCurSp = pet.curSP;
                                petPanel.petMaxSp = pet.maxSP;
                                petPanel.petCurExp = pet.totalExp - Global.expChart[(byte)pet.petType, pet.petLevel - 1];
                                petPanel.petMaxExp = (Global.expChart[(byte)pet.petType, pet.petLevel] - Global.expChart[(byte)pet.petType, pet.petLevel - 1]);
                                petPanel.petClothes = pet.clothes;
                                if (pet.addAtkStatus > 0)
                                {
                                    petPanel.atkStt = pet.atkStatus + " + " + pet.addAtkStatus + " = " + (pet.atkStatus + pet.addAtkStatus);
                                }
                                else if (pet.addAtkStatus < 0)
                                {
                                    petPanel.atkStt = pet.atkStatus + " - " + Math.Abs(pet.addAtkStatus) + " = " + (pet.atkStatus + pet.addAtkStatus);
                                }
                                else
                                {
                                    petPanel.atkStt = pet.atkStatus + " = " + (pet.atkStatus + pet.addAtkStatus);
                                }

                                if (pet.addIntStatus > 0)
                                {
                                    petPanel.intStt = pet.intStatus + " + " + pet.addIntStatus + " = " + (pet.intStatus + pet.addIntStatus);
                                }
                                else if (pet.addIntStatus < 0)
                                {
                                    petPanel.intStt = pet.intStatus + " - " + Math.Abs(pet.addIntStatus) + " = " + (pet.intStatus + pet.addIntStatus);
                                }
                                else
                                {
                                    petPanel.intStt = pet.intStatus + " = " + (pet.intStatus + pet.addIntStatus);
                                }
                                if (pet.addDefStatus > 0)
                                {
                                    petPanel.defStt = pet.defStatus + " + " + pet.addDefStatus + " = " + (pet.defStatus + pet.addDefStatus);
                                }
                                else if (pet.addDefStatus < 0)
                                {
                                    petPanel.defStt = pet.defStatus + " - " + Math.Abs(pet.addDefStatus) + " = " + (pet.defStatus + pet.addDefStatus);
                                }
                                else
                                {
                                    petPanel.defStt = pet.defStatus + " = " + (pet.defStatus + pet.addDefStatus);
                                }

                                if (pet.addAgiStatus > 0)
                                {
                                    petPanel.agiStt = pet.agiStatus + " + " + pet.addAgiStatus + " = " + (pet.agiStatus + pet.addAgiStatus);
                                }
                                else if (pet.addAgiStatus < 0)
                                {
                                    petPanel.agiStt = pet.agiStatus + " - " + Math.Abs(pet.addAgiStatus) + " = " + (pet.agiStatus + pet.addAgiStatus);
                                }
                                else
                                {
                                    petPanel.agiStt = pet.agiStatus + " = " + (pet.agiStatus + pet.addAgiStatus);
                                }

                                petPanel.hpxStt = pet.hpStatus + "";
                                petPanel.spxStt = pet.spStatus + "";
                                petPanel.faiStt = pet.faiStatus + "";
                            }
                            else
                            {
                                petPanel.reset();

                            }
                        }
                    }
                    
                }), new object[] {listPets});
        }

        public void updatePlayerInfo(TsCharacter tsCharacter)
        {
            if (txtPlayerName.InvokeRequired || lblLvl.InvokeRequired || lblEPM.InvokeRequired)
            {
                SetCharacterCallback d = new SetCharacterCallback(updatePlayerInfo);
                if (this != null)
                {
                    this.Invoke(d, new object[] { tsCharacter });
                }
            }
            else
            {
                if (tsCharacter.playerName != null || !tsCharacter.playerName.Trim().Equals(""))
                {
                    txtPlayerName.Text = tsCharacter.playerName;
                }
                lblCurSp.Text = tsCharacter.curSP + "";
                lblCurHp.Text = tsCharacter.curHP + "";
                lblMaxHp.Text = "/ " + tsCharacter.maxHP + "";
                lblMaxSp.Text = "/ " + tsCharacter.maxSP + "";
                lblLvl.Text = tsCharacter.playerLevel + "";
                lblCurExp.Text = (tsCharacter.totalExp - Global.expChart[((byte) tsCharacter.playerType), tsCharacter.playerLevel - 1]) + "";
                lblMaxExp.Text = "/ " + (Global.expChart[(byte)tsCharacter.playerType,  tsCharacter.playerLevel] - Global.expChart[(byte) tsCharacter.playerType, tsCharacter.playerLevel - 1]);
                lblEPM.Text = 0 + "";
                if (thisCharacter.addAgiStatus > 0)
                {
                    lblAgiDetail.Text = thisCharacter.agiStatus + " + " + thisCharacter.addAgiStatus + " = " + (thisCharacter.agiStatus + thisCharacter.addAgiStatus); ;
                }
                else if (thisCharacter.addAgiStatus < 0)
                {
                    lblAgiDetail.Text = thisCharacter.agiStatus + " - " + Math.Abs(thisCharacter.addAgiStatus) + " = " + (thisCharacter.agiStatus + thisCharacter.addAgiStatus); ;
                }
                else
                {
                    lblAgiDetail.Text = thisCharacter.agiStatus + "";
                }
                if (thisCharacter.addAtkStatus > 0)
                {
                    lblAtkDetail.Text = thisCharacter.atkStatus + " + " + thisCharacter.addAtkStatus + " = " + (thisCharacter.atkStatus + thisCharacter.addAtkStatus);
                }
                else if (thisCharacter.addAgiStatus < 0)
                {
                    lblAtkDetail.Text = thisCharacter.atkStatus + " - " + Math.Abs(thisCharacter.addAtkStatus) + " = " + (thisCharacter.atkStatus + thisCharacter.addAtkStatus);
                }
                else
                {
                    lblAtkDetail.Text = thisCharacter.atkStatus + "";
                }
                if (thisCharacter.addDefStatus > 0)
                {
                    lblDefDetail.Text = thisCharacter.defStatus + " + " + thisCharacter.addDefStatus + " = " + (thisCharacter.defStatus + thisCharacter.addDefStatus);
                }
                else if (thisCharacter.addAgiStatus < 0)
                {
                    lblDefDetail.Text = thisCharacter.defStatus + " - " + Math.Abs(thisCharacter.addDefStatus) + " = " + (thisCharacter.defStatus + thisCharacter.addDefStatus);
                }
                else
                {
                    lblDefDetail.Text = thisCharacter.defStatus + "";
                }
                if (thisCharacter.addIntStatus > 0)
                {
                    lblIntDetail.Text = thisCharacter.intStatus + " + " + thisCharacter.addIntStatus + " = " + (thisCharacter.intStatus + thisCharacter.addIntStatus);
                }
                else if (thisCharacter.addIntStatus < 0)
                {
                    lblIntDetail.Text = thisCharacter.intStatus + " - " + Math.Abs(thisCharacter.addIntStatus) + " = " + (thisCharacter.intStatus + thisCharacter.addIntStatus);
                }
                else
                {
                    lblIntDetail.Text = thisCharacter.intStatus + "";
                }
                lblHpxDetail.Text = thisCharacter.hpStatus + "";
                lblSpxDetail.Text = thisCharacter.spStatus + "";
                grpStatus.Text = "Point Left: " + thisCharacter.statusPointLeft;
                switch (tsCharacter.playerElement)
                {
                    case PlayerElement.FIRE:
                        txtPlayerName.BackColor = Color.Red;
                        break;
                    case PlayerElement.EARTH:
                        txtPlayerName.BackColor = Color.SaddleBrown;
                        break;
                    case PlayerElement.WATER:
                        txtPlayerName.BackColor = Color.AliceBlue;
                        break;
                    case PlayerElement.WIND:
                        txtPlayerName.BackColor = Color.LawnGreen;
                        break;
                }
            }
        }

        public void updatePlayerInventory(PlayerItem[] items) {
            if (lstInventory.InvokeRequired)
            {
                SetInventoryCallback d = new SetInventoryCallback(updatePlayerInventory);
                this.BeginInvoke(d, new object[] {items});
            }
            else
            {
                if (thisCharacter != null)
                {
                    thisCharacter.inventory = items;
                }
                else
                {
                    thisCharacter = new TsCharacter { playerId = userId };
                    thisCharacter.inventory = items;
                }
                if (items != null)
                {
                    lstInventory.Items.Clear();
                    for (int i = 0; i < items.Length; i++)
                    {
                        PlayerItem itemData = thisCharacter.inventory[i];
                        ListViewItem inventoryItem = new ListViewItem((i + 1).ToString());
                        if (itemData != null)
                        {
                            inventoryItem.SubItems.AddRange(new string[] { itemData.name, itemData.quantity.ToString(), itemData.wearLvl.ToString() });
                            inventoryItem.Tag = itemData;
                            inventoryItem.ToolTipText = itemData.description;
                        }
                        lstInventory.Items.Add(inventoryItem);
                    }
                    lstInventory.MouseDown += new MouseEventHandler(lstInventory_MouseDown);
                }
                
            }
        }
        public void updateCharUniforms(PlayerItem[] uniforms)
        {
            if (lstClothes.InvokeRequired)
            {
                if (uniforms != null)
                {
                    SetUniformCallback d = new SetUniformCallback(updateCharUniforms);
                    lstClothes.BeginInvoke(d, new object[] {uniforms });
                }
            }
            else
            {
                if (uniforms != null)
                {
                    lstClothes.Items.Clear();
                    foreach (PlayerItem item in uniforms)
                    {
                        ListViewItem clothesItem = new ListViewItem("");
                        if (item != null)
                        {
                            clothesItem = new ListViewItem(item.name);
                            clothesItem.SubItems.Add(item.wearLvl.ToString());
                        }
                        lstClothes.Items.Add(clothesItem);
                    }
                }
                
                
            }
        }
        public void addPlayerToList(List<Player> players)
        {
            if (lstPlayer.InvokeRequired)
            {
                SetPlayerCallback d = new SetPlayerCallback(addPlayerToList);
                    //this.Invoke(d, new object[] { players });
                lstPlayer.BeginInvoke(d, new object[] { players });
            }
            else
            {
                foreach (Player playerData in players)
                {
                    if (!playerList.Contains(playerData, new PlayerComparator()))
                    {
                        playerList.Add(playerData);
                        ListViewItem playerItem = new ListViewItem("ON");
                        playerItem.SubItems.AddRange(new string[] { playerData.playerId.ToString(), playerData.playerName, playerData.playerLevel.ToString(), playerData.currentMap.ToString(), playerData.playerElement.ToString(), playerData.playerType.ToString() });
                        lstPlayer.Items.Add(playerItem);
                    }
                }
                lblTotalOnline.Text = "Total: " + playerList.Count;
                
            }
        }

        public void updatePacket(List<TsMessage> messages)
        {
            List<Player> bufferPlayers = new List<Player>();
            Pet[] petBuffer = null;
            PlayerItem[] inventoryItems = null;
            PlayerItem[] charUniforms = null;
            bool doneCharacter = false;
            foreach (TsMessage message in messages)
            {
                //Debug.WriteLine(message.ToString() + "\n");
                
                #region New Player Online
                if (message.opCode.Equals(CommandConstants.ONLINE_COMMAND))
                {
                    int startPos = 0;
                    long playerId = WSUtils.decodeNumber(message.data, 0, 4);
                    startPos += 4;
                    byte playerLvl = 0x00;
                    PlayerElement playerEle = PlayerElement.FIRE;
                    PlayerSex sex = (PlayerSex)message.data[startPos];
                    startPos += 1;
                    if (playerId != userId)
                    {
                        playerEle = (PlayerElement)message.data[startPos];
                        startPos += 1;
                        playerLvl = message.data[startPos];
                        startPos += 1;
                    }
                    int numGhost = WSUtils.decodeNumber(message.data, startPos, 1);
                    startPos += 1;
                    int numGod = WSUtils.decodeNumber(message.data, startPos, 1);
                    startPos += 1;
                    int mapId = WSUtils.decodeNumber(message.data, startPos, 2);
                    startPos += 2;
                    short xCoord = (short)WSUtils.decodeNumber(message.data, startPos, 2);
                    startPos += 2;
                    short yCoord = (short)WSUtils.decodeNumber(message.data, startPos, 2);
                    startPos += 2;
                    int gap = 11;
                    startPos += gap;
                    int numberOfClothes = (int)WSUtils.decodeNumber(message.data, startPos, 1);
                    startPos += 1;
                    if (numberOfClothes > 0)
                    {
                        gap = 2 * numberOfClothes;
                    }
                    else
                    {
                        gap = 0;
                    }
                    if (playerId == userId)
                    {
                        startPos += (gap + 5);
                    }
                    else
                    {
                        startPos += (gap + 6);
                    }
                    
                    PlayerType playerType = (PlayerType)message.data[startPos];
                    startPos += 2;
                    string playerName = WSUtils.decodeString(message.data, startPos, (int)message.length - startPos);
                    if (playerId == userId)
                    {
                        if (thisCharacter == null)
                        {
                            thisCharacter = new TsCharacter { playerId = userId };
                        }
                        else
                        {
                            if (thisCharacter.maxHP != 0)
                            {
                                doneCharacter = true;
                            }
                            
                        }
                        thisCharacter.playerName = playerName;
                        thisCharacter.playerType = playerType;
                        thisCharacter.currentMap = mapId;
                        thisCharacter.playerSex = sex;
                        thisCharacter.numGod = numGod;
                        thisCharacter.numGhost = numGhost;
                    }
                    else
                    {
                        Player player = new Player();
                        player.playerId = playerId;
                        player.playerName = playerName;
                        player.playerLevel = playerLvl;
                        player.playerSex = sex;
                        player.playerType = playerType;
                        player.playerElement = playerEle;
                        player.currentMap = mapId;
                        player.xCoord = xCoord;
                        player.yCoord = yCoord;
                        if (!bufferPlayers.Contains(player, new PlayerComparator()))
                        {
                            bufferPlayers.Add(player);
                        }
                    }
                }
                #endregion
                #region Onlined Player
                else if (message.opCode.Equals(CommandConstants.PLAYER_COMMAND))
                {

                    int startPos = 0;
                    long playerId = WSUtils.decodeNumber(message.data, 0, 4);
                    PlayerSex sex = (PlayerSex)message.data[4];
                    PlayerElement playerEle = (PlayerElement)message.data[5];
                    byte playerLevel = message.data[6];
                    int numGhost = WSUtils.decodeNumber(message.data, 7, 1);
                    int numGod = WSUtils.decodeNumber(message.data, 8, 1);
                    int mapId = WSUtils.decodeNumber(message.data, 9, 2);
                    short xCoord = (short)WSUtils.decodeNumber(message.data, 11, 2);
                    short yCoord = (short)WSUtils.decodeNumber(message.data, 13, 2);
                    int gap = 11;
                    byte numberOfClothes = message.data[15 + gap];
                    startPos = 15 + gap;
                    if (numberOfClothes > 0)
                    {
                        gap = 1 + 2 * numberOfClothes;
                    }
                    else
                    {
                        gap = 1;
                    }
                    startPos = startPos + gap + 6;
                    PlayerType playerType = (PlayerType)message.data[startPos];
                    startPos += 2;
                    string playerName = WSUtils.decodeString(message.data, startPos, (int)message.length - startPos);
                    if (playerId != userId)
                    {
                        Player player = new Player();
                        player.playerId = playerId;
                        player.playerName = playerName;
                        player.playerLevel = playerLevel;
                        player.playerSex = sex;
                        player.playerType = playerType;
                        player.playerElement = playerEle;
                        player.currentMap = mapId;
                        player.xCoord = xCoord;
                        player.yCoord = yCoord;
                        if (!bufferPlayers.Contains(player, new PlayerComparator()))
                        {
                            bufferPlayers.Add(player);
                        }
                    }

                }
                #endregion
                #region Player Info
                else if (message.opCode.Equals(CommandConstants.PLAYER_INFO_COMMAND))
                {
                    Debug.WriteLine(message.ToString() + "\n");
                    int startPos = 0;
                    PlayerElement playerEle = (PlayerElement)message.data[startPos];
                    startPos++;
                    int curHp = WSUtils.decodeNumber(message.data, startPos, 2);
                    startPos += 2;
                    int curSp = WSUtils.decodeNumber(message.data, startPos, 2);
                    startPos += 2;
                    int intStt = WSUtils.decodeNumber(message.data, startPos, 2);
                    startPos += 2;
                    int atkStt = WSUtils.decodeNumber(message.data, startPos, 2);
                    startPos += 2;
                    int defStt = WSUtils.decodeNumber(message.data, startPos, 2);
                    startPos += 2;
                    int agiStt = WSUtils.decodeNumber(message.data, startPos, 2);
                    startPos += 2;
                    int hpxStt = WSUtils.decodeNumber(message.data, startPos, 2);
                    startPos += 2;
                    int spxStt = WSUtils.decodeNumber(message.data, startPos, 2);
                    startPos += 2;
                    byte playerLevel = message.data[startPos];
                    startPos += 1;
                    int tExp = WSUtils.decodeNumber(message.data, startPos, 4);
                    startPos += 4;
                    int skillPointLeft = WSUtils.decodeNumber(message.data, startPos, 2);
                    startPos += 2;
                    int statusPointLeft = WSUtils.decodeNumber(message.data, startPos, 2);
                    startPos += 2;
                    int honor = WSUtils.decodeNumber(message.data, startPos, 4);
                    startPos += 4;
                    int maxHp = WSUtils.decodeNumber(message.data, startPos, 2);
                    startPos += 2;
                    int maxSp = WSUtils.decodeNumber(message.data, startPos, 2);
                    startPos += 2;
                    int addAtkStatus = WSUtils.decodeNumber(message.data, startPos, 4);
                    startPos += 4;
                    int addDefStatus = WSUtils.decodeNumber(message.data, startPos, 4);
                    startPos += 4;
                    int addIntStatus = WSUtils.decodeNumber(message.data, startPos, 4);
                    startPos += 4;
                    int addAgiStatus = WSUtils.decodeNumber(message.data, startPos, 4);
                    startPos += 4;
                    int addMaxHP = WSUtils.decodeNumber(message.data, startPos, 4);
                    startPos += 4;
                    int addMaxSP = WSUtils.decodeNumber(message.data, startPos, 4);
                    startPos += 4;
                    startPos += 56;
                    List<TsSkill> skills = new List<TsSkill>();
                    for (int i = startPos; i < message.length - startPos; i+=3)
                    {
                        int skillId = WSUtils.decodeNumber(message.data, startPos, 2);
                        TsSkill skill = null;
                        Global.globalSkills.TryGetValue(skillId,out skill);
                        if (skill != null)
                        {
                            skills.Add(skill);
                        }
                        else
                        {
                            Debug.WriteLine("Skill not found " + skillId);
                        }
                    }

                    if (thisCharacter == null)
                    {
                        thisCharacter = new TsCharacter { playerId = userId };
                    }
                    else
                    {
                        doneCharacter = true;
                    }
                    thisCharacter.playerElement = playerEle;
                    thisCharacter.playerLevel = playerLevel;
                    thisCharacter.totalExp = tExp;
                    thisCharacter.curHP = curHp;
                    thisCharacter.curSP = curSp;
                    thisCharacter.maxHP = maxHp;
                    thisCharacter.maxSP = maxSp;
                    thisCharacter.intStatus = intStt;
                    thisCharacter.atkStatus = atkStt;
                    thisCharacter.defStatus = defStt;
                    thisCharacter.hpStatus = hpxStt;
                    thisCharacter.spStatus = spxStt;
                    thisCharacter.agiStatus = agiStt;
                    thisCharacter.addIntStatus = addIntStatus;
                    thisCharacter.addAtkStatus = addAtkStatus;
                    thisCharacter.addDefStatus = addDefStatus;
                    thisCharacter.addAgiStatus = addAgiStatus;
                    thisCharacter.addMaxHP = addMaxHP;
                    thisCharacter.addMaxSP = addMaxSP;
                    //thisCharacter.skills = skills.ToArray();
                }
                #endregion
                #region Player Uniform
                else if (message.opCode.Equals(CommandConstants.PLAYER_UNIFORM_COMMAND))
                {
                    charUniforms = new PlayerItem[6];
                    for (int i = 0; i < message.length / 10; i++) {
                        int startPos = i*10;
                        int itemId = WSUtils.decodeNumber(message.data, startPos, 2);
                        startPos += 2;
                        byte wearLvl = message.data[startPos];
                        PlayerItem newUniform = new PlayerItem(); 
                        newUniform.itemId = itemId;
                        newUniform.quantity = 1;
                        newUniform.wearLvl = wearLvl;
                        TsItem storedItem = null;
                        Global.globalItems.TryGetValue(itemId, out storedItem);
                        if (storedItem != null)
                        {
                            newUniform.name = storedItem.name;
                            newUniform.description = storedItem.description;
                        }
                        else
                        {
                            newUniform.name = itemId + "";
                        }
                        if (newUniform.itemType <= ItemType.BADGE)
                        {
                            charUniforms[(int)newUniform.itemType] = newUniform;
                        }
                    }
                }
                #endregion
                #region Player Inventory
                else if (message.opCode.Equals(CommandConstants.PLAYER_INVENTORY_COMMAND))
                {
                    inventoryItems = new PlayerItem[25];
                    for (int i = 0; i < (message.length / 12); i++)
                    {
                        int startPos = i*12;
                        byte index = message.data[startPos];
                        startPos++;
                        int itemId = WSUtils.decodeNumber(message.data, startPos, 2);
                        startPos+=2;
                        byte quantity = message.data[startPos];
                        startPos++;
                        byte wearLvl = message.data[startPos];
                        startPos++;
                        if (itemId != 0)
                        {
                            PlayerItem newItem = new PlayerItem();
                            newItem.itemId = itemId;
                            newItem.wearLvl = wearLvl;
                            newItem.quantity = quantity;
                            TsItem storedItem = null;

                            if (Global.globalItems != null)
                            {
                                Global.globalItems.TryGetValue(itemId, out storedItem);
                            }
                            if (storedItem != null)
                            {
                                newItem.name = storedItem.name;
                                newItem.description = storedItem.description;
                            }
                            else
                            {
                                newItem.name = newItem.itemId + "";
                            }

                            inventoryItems[index - 1] = newItem;
                        }
                        else
                        {
                            inventoryItems[index - 1] = null;
                        }
                        
                    }
                }
                #endregion
                #region Pet Info
                else if (message.opCode.Equals(CommandConstants.PET_INFO_COMMAND))
                {
                    petBuffer = new Pet[6];
                    int startPos = 0;
                    while (startPos < message.length)
                    {
                        int index = (int)message.data[startPos];
                        startPos++;
                        int petId = WSUtils.decodeNumber(message.data, startPos, 2);
                        startPos += 2;
                        int tExp = WSUtils.decodeNumber(message.data, startPos, 4);
                        startPos += 4;
                        byte lvl = message.data[startPos];
                        startPos++;
                        int maxHp = WSUtils.decodeNumber(message.data, startPos, 2);
                        startPos += 2;
                        int maxSp = WSUtils.decodeNumber(message.data, startPos, 2);
                        startPos += 2;
                        int intStt = WSUtils.decodeNumber(message.data, startPos, 2);
                        startPos += 2;
                        int atkStt = WSUtils.decodeNumber(message.data, startPos, 2);
                        startPos += 2;
                        int defStt = WSUtils.decodeNumber(message.data, startPos, 2);
                        startPos += 2;
                        int agiStt = WSUtils.decodeNumber(message.data, startPos, 2);
                        startPos += 2;
                        int hpStt = WSUtils.decodeNumber(message.data, startPos, 2);
                        startPos += 2;
                        int spStt = WSUtils.decodeNumber(message.data, startPos, 2);
                        startPos += 2;
                        startPos += 1;
                        byte fai = message.data[startPos];
                        startPos += 1;
                        startPos += 3;
                        byte nameLength = message.data[startPos];
                        startPos += 1;
                        string petName = WSUtils.decodeString(message.data, startPos, nameLength);
                        startPos += nameLength;
                        startPos += 3;
                        PlayerItem[] petClothes = new PlayerItem[6];
                        for (int i = startPos; i < startPos + 60; i+=10)
                        {
                            int itemId = WSUtils.decodeNumber(message.data, i, 2);
                            if (itemId != 0)
                            {
                                byte wearLvl = message.data[i + 2];
                                TsItem storedItem = null;
                                Global.globalItems.TryGetValue(itemId, out storedItem);
                                PlayerItem petItem = new PlayerItem { itemId = itemId, name = "", description = "", wearLvl = wearLvl };
                                if (storedItem != null)
                                {
                                    petItem.name = storedItem.name;
                                    petItem.description = storedItem.description;
                                }
                                if (petItem.itemType >= ItemType.HAT && petItem.itemType <= ItemType.BADGE)
                                {
                                    petClothes[(int)petItem.itemType] = petItem;
                                }
                                else
                                {
                                    Debug.WriteLine("ITEM NOT APPROPRIATE " + itemId);
                                }
                            }
                        }
                        startPos += 60;
                        startPos += 6;
                        Pet newPet = new Pet(petId, petName);
                        newPet.intStatus = intStt;
                        newPet.agiStatus = agiStt;
                        newPet.atkStatus = atkStt;
                        newPet.defStatus = defStt;
                        newPet.hpStatus = hpStt;
                        newPet.spStatus = spStt;
                        newPet.maxHP = maxHp;
                        newPet.maxSP = maxSp;
                        newPet.petLevel = lvl;
                        newPet.totalExp = tExp;
                        newPet.clothes = petClothes;
                        newPet.faiStatus = fai;
                        petBuffer[index - 1] = newPet;
                    }
                    if (petBuffer != null)
                    {
                        updatePetInfo(petBuffer);
                    }

                }
                #endregion
                else if (message.opCode.Equals(CommandConstants.PLAYER_DEFAULT_PET))
                {
                    int startPos = 0;
                    int petId = WSUtils.decodeNumber(message.data, startPos, 2);
                    updateDefaultPet(petId);
                }
                else if (message.opCode.Equals(CommandConstants.UPDATE_PLAYER_ATTR)) 
                {
                    int startPos = 0;
                    byte type = message.data[startPos];
                    startPos++;
                    byte isNegative = message.data[startPos];
                    startPos++;
                    int value = WSUtils.decodeNumber(message.data, startPos, 4);
                    if (isNegative == 0x02)
                    {
                        value = -value;
                    }
                    updatePlayerAttr(type, value);
                } 
                else if (message.opCode.Equals(CommandConstants.UPDATE_PET_ATTR))
                {
                    Debug.WriteLine(message.ToString() + "\n");
                    int startPos = 1;
                    int index = (int) message.data[startPos];
                    startPos += 2;
                    byte type = message.data[startPos];
                    startPos++;
                    byte isNegative = message.data[startPos];
                    startPos++;
                    int value = WSUtils.decodeNumber(message.data, startPos, 4);
                    if (isNegative == 0x02) 
                    {
                        value = -value;
                    }
                    updatePetAttr(index, type, value);
                }
                //} else if (message.opCode.Equals(CommandConstants.
                
            } 
            if (bufferPlayers.Count > 0)
            {
                addPlayerToList(bufferPlayers);
            }
            if (doneCharacter)
            {
                updatePlayerInfo(thisCharacter);
            }
            if (inventoryItems != null)
            {
                updatePlayerInventory(inventoryItems);
            }
            if (charUniforms != null)
            {
                updateCharUniforms(charUniforms);
            }
            
            
        }
        public void ListenThread()
        {
            updateLog("Listening...\n");
            byte[] myBuffer = new byte[10000];
            int byteReceived = 0;
            int i = 0;
            byte[] remainBytes = null;
            TcpClient tcpClient = WSUtils.getTCPClient();
            List<TsMessage> bufferMessages = new List<TsMessage>();
            while (bActive) {
                
                
                //StateObject stateObject = new StateObject();
                //stateObject.workSocket = tcpClient.Client;

                byteReceived = tcpClient.GetStream().Read(myBuffer, 0, 8192);
                if (bufferMessages.Count > 0)
                {
                    updatePacket(bufferMessages);
                    bufferMessages.Clear();
                }
                

                if (byteReceived > 0)
                {
                    updatePacketCount();
                    i = 0;
                    byte[] dataReceived = WSUtils.decodePacket(myBuffer, byteReceived);
                    //remainBytes = parsePacket(dataReceived, lData, remainBytes);
                    //Debug.WriteLine(WSUtils.printBytes(myBuffer, lData));
                    byte[] proceedData = null;
                    try
                    {
                        if (remainBytes != null)
                        {
                            proceedData = new byte[remainBytes.Length + byteReceived];
                            Array.Copy(remainBytes, 0, proceedData, 0, remainBytes.Length);
                            Array.Copy(dataReceived, 0, proceedData, remainBytes.Length, byteReceived);
                        }
                        else
                        {
                            proceedData = dataReceived;

                        }
                        //updateLog("Processed " + WSUtils.printBytes(dataReceived, byteReceived) + "\n");
                        if (proceedData.Length < 4)
                        {
                            remainBytes = proceedData;
                        }
                        else
                        {
                            //length >=4
                            int startDataPos = 0;
                            while (startDataPos < proceedData.Length)
                            {
                                if (proceedData.Length - startDataPos < 4)
                                {
                                    remainBytes = new byte[proceedData.Length - startDataPos];
                                    Array.Copy(proceedData, startDataPos, remainBytes, 0, remainBytes.Length);
                                    break;
                                }
                                else
                                {
                                    if (proceedData[startDataPos] == 0xF4 && proceedData[startDataPos + 1] == 0x44)
                                    {
                                        //has Header
                                        int length = WSUtils.decodeNumber(proceedData, startDataPos + 2, 2);
                                        if (proceedData.Length < startDataPos + length + 4)
                                        {
                                            remainBytes = proceedData;
                                            break;
                                        }
                                        else
                                        {
                                            TsMessage receivedMessage = new TsMessage(length, proceedData, startDataPos + 4);
                                            startDataPos = startDataPos + 4 + length;
                                            //updatePacket(receivedMessage);
                                            bufferMessages.Add(receivedMessage);
                                            remainBytes = null;
                                        }
                                    }
                                    else
                                    {
                                        remainBytes = new byte[proceedData.Length - startDataPos];
                                        Array.Copy(proceedData, startDataPos, remainBytes, 0, remainBytes.Length);
                                        //updateLog("UNKNOWN PACKET " + startDataPos + " " + WSUtils.printBytes(remainBytes, remainBytes.Length) + "\n");
                                        remainBytes = null;
                                        break;
                                    }
                                }

                            }

                        }
                    }
                    catch (Exception e)
                    {
                        updateLog(e.Message + "\n" + e.StackTrace);
                    }
                    //break;
                    //Thread.Sleep(500);*/
                    //Debug.WriteLine(WSUtils.printBytes(dataReceived, byteReceived));
                    //updateLog(WSUtils.printBytes(dataReceived, byteReceived) + "\n");
                    Thread.Sleep(50);
                }
                else
                {
                    
                    Thread.Sleep((i + 1)*200);
                    i++;
                    if (i > 5)
                    {
                        i = 0;
                    }
                }
                //tcpClient.Client.BeginReceive(stateObject.Buffer, 0, StateObject.BUFFER_SIZE, 0, new AsyncCallback(receiveCallback), stateObject);
                //Thread.Sleep(200);
                
            }
            timerUpdateTime.Enabled = false;
            //ClearAll here
            //Debug.WriteLine(WSUtils.printBytes(remainBytes, remainBytes.Length));
            
        }

        private void btnDisconnect_Click(object sender, EventArgs e)
        {
            updateLog("Connection Closed", false);
            if (listenThread != null)
            {
                bActive = false;
                listenThread.Join();
            }
            WSUtils.closeSocket(0);

        }

        private void button1_Click(object sender, EventArgs e)
        {
            string decNumber = txtNumeric.Text;
            rtResult.Text += WSUtils.encodeNumber(int.Parse(decNumber), 4) + "\n";
        }

        private void button2_Click(object sender, EventArgs e)
        {
            string decNumber = txtNumeric2.Text;
            rtResult.Text += WSUtils.decodeNumber(decNumber, decNumber.Length/2) + "\n";
        }

        private void timerUpdateTime_Tick(object sender, EventArgs e)
        {
            long time = 0L;
            if (tstripLblTime.Tag == null) {
                tstripLblTime.Tag = 1L;
                time = 1L;
                tstripLblTime.Text = "Elasped: " + time;
            } else {
                time = (long) tstripLblTime.Tag;
                time++;
                tstripLblTime.Tag = time;
                tstripLblTime.Text = "Elasped: " + time;
            }
            
        }

        /*
         * Return remain packet
         */
        public byte[] parsePacket(byte[] dataReceived, int byteReceived, byte[] unfinishedPacket)
        {
            byte[] remain = null;
            byte[] proceedData = null;
            try
            {
                if (unfinishedPacket != null)
                {
                    proceedData = new byte[unfinishedPacket.Length + byteReceived];
                    Array.Copy(unfinishedPacket, 0, proceedData, 0, unfinishedPacket.Length);
                    Array.Copy(dataReceived, 0, proceedData, unfinishedPacket.Length, byteReceived);
                }
                else
                {
                    proceedData = dataReceived;

                }
                if (proceedData.Length < 4)
                {
                    remain = proceedData;
                }
                else
                {
                    //length >=4
                    int startDataPos = 0;
                    while (startDataPos < proceedData.Length)
                    {
                        if (proceedData.Length - startDataPos < 4)
                        {
                            remain = new byte[proceedData.Length - startDataPos];
                            Array.Copy(proceedData, startDataPos, remain, 0, remain.Length);
                            break;
                        }
                        else
                        {
                            if (proceedData[startDataPos] == 0xF4 && proceedData[startDataPos + 1] == 0x44)
                            {
                                //has Header
                                int length = (int)WSUtils.decodeNumber(proceedData, startDataPos + 2, 2);
                                if (proceedData.Length < startDataPos + length - 4)
                                {
                                    remain = proceedData;
                                    break;
                                }
                                else
                                {
                                    TsMessage receivedMessage = new TsMessage(length, proceedData, startDataPos + 4);
                                    startDataPos = startDataPos + length + 1;
                                    updateLog(receivedMessage.ToString() + "\n");
                                    remain = null;
                                }
                            }
                            else
                            {
                                remain = new byte[proceedData.Length - startDataPos];
                                Array.Copy(proceedData, startDataPos, remain, 0, remain.Length);
                                updateLog("UNKNOWN PACKET " + startDataPos + " " + WSUtils.printBytes(remain, remain.Length) + "\n");
                                remain = null;
                                break;
                            }
                        }

                    }

                }
            }
            catch (Exception e)
            {
                updateLog(e.Message + "\n" + e.StackTrace);
            }
            return remain;

        }
        private void disableUserAction()
        {
            btnAddAgi.Enabled = false;
            btnAddAtk.Enabled = false;
            btnAddDef.Enabled = false;
            btnAddHpx.Enabled = false;
            btnAddInt.Enabled = false;
            btnAddSpx.Enabled = false;
            petDetail1.disableActive();
            petDetail2.disableActive();
            petDetail3.disableActive();
            petDetail4.disableActive();

        }
        private void enableUserAction()
        {
            btnAddAgi.Enabled = true;
            btnAddAtk.Enabled = true;
            btnAddDef.Enabled = true;
            btnAddHpx.Enabled = true;
            btnAddInt.Enabled = true;
            btnAddSpx.Enabled = true;
            petDetail1.enableActive();
            petDetail2.enableActive();
            petDetail3.enableActive();
            petDetail4.enableActive();

        }
        private void clearAll()
        {
            petDetail1.reset();
            petDetail2.reset();
            petDetail3.reset();
            petDetail4.reset();
        }
        private void lblLvl_TextChanged(object sender, EventArgs e)
        {
            lblDetailLvl.Text = lblLvl.Text;
        }

        private void lblCurHp_TextChanged(object sender, EventArgs e)
        {
            lblDetailHp.Text = lblCurHp.Text;
        }

        private void lblMaxHp_TextChanged(object sender, EventArgs e)
        {
            lblDetailMaxHp.Text = lblMaxHp.Text;
        }

        private void lblCurSp_TextChanged(object sender, EventArgs e)
        {
            lblDetailCurSp.Text = lblCurSp.Text;
        }

        private void lblMaxSp_TextChanged(object sender, EventArgs e)
        {
            lblDetailMaxSp.Text = lblMaxSp.Text;
        }

        private void lblCurExp_TextChanged(object sender, EventArgs e)
        {
            lblDetailCurExp.Text = lblCurExp.Text;
        }

        private void txtPlayerName_TextChanged(object sender, EventArgs e)
        {
            lblNameDetail.Text = txtPlayerName.Text;
        }

        private void lblMaxExp_TextChanged(object sender, EventArgs e)
        {
            lblDetailMaxExp.Text = lblMaxExp.Text;
        }

        private void petDetail1_ActivePet(object senders, EventArgs args)
        {
            if (thisCharacter.carryPet[0] != null)
            {
                if (petDetail1.IsActive)
                {

                }
                else
                {

                }
            }
        }
    }
}
